-- Parsec
-- Module 'templates'
function pBasic(s)
  s.articles["Look"] = nvl(s.articles["Look"],"на");
  s.articles["ListenTo"] = nvl(s.articles["ListenTo"],"к");
  s.articles["Pounce"] = nvl(s.articles["Pounce"],"на");
  s.articles["Shoot"] = nvl(s.articles["Shoot"],"в");
  s.articles["Approach"] = nvl(s.articles["Approach"],"к");
  if s.Exam ~= nil then
    s.Look = nvl(s.Look, redirect_("Exam"));
  end
  if s.Listen ~= nil then
    s.ListenTo = nvl(s.ListenTo, redirect_("Listen"));
  end
  if s.Attack ~= nil then
    s.Pounce = nvl(s.Pounce, redirect_("Attack"));
    s.Kick = nvl(s.Kick, redirect_("Attack"));
  end
  if s.Approach ~= nil then
    s.Walk = nvl(s.Walk, redirect_("Approach"));
  elseif s.Walk ~= nil then
    s.Approach = nvl(s.Approach, redirect_("Walk"));
  end
  if s.Open ~= nil then
    s.Close = nvl(s.Close, nilfn);
  end
  if s.Talk ~= nil then
    s.Reply = nvl(s.Reply, redirect_("Talk"));
  end
  if s.TearOff ~= nil then
    s.TakeOff = nvl(s.TakeOff, redirect_("TearOff"));
  end
  if s.Tear ~= nil then
    s.Wreck = nvl(s.Wreck, redirect_("Tear"));
  end
  if s.Move ~= nil then
    s.Spin = nvl(s.Spin, nilfn);
  end
  if s.TurnOn ~= nil then
    s.Activate = nvl(s.Activate, redirect_("TurnOn"));
  end
  return s;
end

function pFloor(s)
  pBasic(s);
  s.kind_ = "floor";
  s.break_ = false;
  s.withThrow = true;
  s.withPut = true;
  s.withPutAway = true;
  s.withPure = true;
  s.articles["Throw"] = nvl(s.articles["Throw"],"на");
  s.articles["Put"] = nvl(s.articles["Put"],"на");
  s.articles["PutAway"] = nvl(s.articles["PutAway"],"на");
  s.articles["Sit"] = nvl(s.articles["Sit"],"на");
  s.articles["Lie"] = nvl(s.articles["Lie"],"на");
  s.articles["Descend"] = nvl(s.articles["Descend"],"на");
  s.articles["Stand"] = nvl(s.articles["Stand"],"с");
  s.articles["Pure"] = nvl(s.articles["Pure"],"на");
  s.articles["Search"] = nvl(s.articles["Search"],"на");
  if s.Put ~= nil then
    s.PutAway = nvl(s.PutAway, redirect_("Put"));
  end
  s.Descend = nvl(s.Descend, redirect_("Lie"));
  s.Sit = nvl(s.Sit, nilfn);
  s.Lie = nvl(s.Lie, nilfn);
  s.Stand = nvl(s.Stand, "Я не сижу на полу.");
  return s;
end

function pCeil(s)
  pBasic(s);
  s.kind_ = "ceil";
  s.break_ = false;
  s.withThrow = true;
  s.articles["Throw"] = nvl(s.articles["Throw"],"в");
  s.articles["Ascend"] = nvl(s.articles["Ascend"],"на");
  s.Ascend = nvl(s.Ascend, nilfn);
  return s;
end

--A wall, a column, etc.
function pBuild(s)
  pBasic(s);
  s.break_ = false;
  s.withThrow = true;
  s.withPure = true;
  s.articles["Throw"] = nvl(s.articles["Throw"],"в");
  s.articles["Walk"] = nvl(s.articles["Walk"],"к");
  s.articles["Ascend"] = nvl(s.articles["Ascend"],"на");
  s.articles["Pure"] = nvl(s.articles["Pure"],"на");
  s.articles["Search"] = nvl(s.articles["Search"],"у");
  s.Wreck = nvl(s.Wreck, nilfn);
  s.Ascend = nvl(s.Ascend, nilfn);
  return s;
end

function pWindow(s)
  s.articles["Look"] = nvl(s.articles["Look"],"в");
  pBuild(s);
  s.break_ = true;
  s.kind_ = "window";
  s.Open = nvl(s.Open, "Я не уверен, что это окно вообще можно открыть. Да и зачем мне его открывать?");
  s.Close = nvl(s.Close, "Окно закрыто.");
  s.Move = nvl(s.Move, "Не представляю, как это можно сделать.");
  s.Wreck = nvl(s.Wreck, "Не думаю, что разбить окно -- это хорошая идея.");
  return s;
end

function pWall(s)
  s.Open = nvl(s.Open, "Стены не открываются. По крайней мере, если я ещё не сошёл с ума.");
  s.Close = nvl(s.Close, nilfn);
  s.Approach = nvl(s.Approach, "Я подхожу к ближайшей стене и встаю напротив неё.");
  pBuild(s);
  s.kind_ = "wall";
  s.withTakeOff = true;
  s.withTearOff = true;
  s.withShoot = true;
  s.articles["Shoot"] = nvl(s.articles["Shoot"],"в");
  s.articles["TakeOff"] = nvl(s.articles["TakeOff"],"со");
  s.articles["TearOff"] = nvl(s.articles["TearOff"],"со");
  s.Move = nvl(s.Move, "Сомневаюсь, что у меня получится сдвинуть стену.");
  return s;
end

function pTable(s)
  s.Approach = nvl(s.Approach, "Я подхожу к столу и опираюсь на него одной рукой.");
  s.articles["Search"] = nvl(s.articles["Search"],"под");
  pBuild(s);
  s.kind_ = "table";
  s.break_ = true;
  s.withPut = true;
  s.withPutIn = true;
  s.withPutAway = true;
  s.withTakeFrom = true;
  s.articles["Stand"] = nvl(s.articles["Stand"],"из-за");
  s.articles["Lie"] = nvl(s.articles["Lie"],"на");
  s.articles["Ascend"] = nvl(s.articles["Ascend"],"на");
  s.articles["Descend"] = nvl(s.articles["Descend"],"со");
  s.articles["Sit"] = nvl(s.articles["Sit"],"за");
  s.articles["Put"] = nvl(s.articles["Put"],"на");
  s.articles["PutAway"] = nvl(s.articles["PutAway"],"на");
  s.articles["PutIn"] = nvl(s.articles["PutIn"],"на");
  s.articles["TakeFrom"] = nvl(s.articles["TakeFrom"],"со");
  s.Lie = nvl(s.Lie, nilfn);
  s.Ascend = nvl(s.Ascend, redirect_("Lie"));
  s.Descend = nvl(s.Descend, "К счастью, я не лежу на столе.");
  s.Stand = nvl(s.Stand,nilfn);
  s.Sit = nvl(s.Sit,nilfn);
  s.Open = nvl(s.Open, "В этом столе нет никаких ящиков или отделений. Открывать тут нечего.");
  s.Close = nvl(s.Close, "В столе нет отделений, я не очень понимаю, как его можно закрыть.");
  s.Move = nvl(s.Move, "Стол довольно тяжёлый, чтобы двигать его туда-сюда от нечего делать.");
  s.Take = nvl(s.Take, "Боюсь, стол мне не унести.");
  return s;
end

function pChair(s)
  s.articles["Search"] = nvl(s.articles["Search"],"под");
  s.Approach = nvl(s.Approach, "Я подхожу к стулу и останавливаюсь напротив него.");
  pBuild(s);
  s.kind_ = "chair";
  s.break_ = true;
  s.withPut = true;
  s.withPutIn = true;
  s.withPutAway = true;
  s.articles["Stand"] = nvl(s.articles["Stand"],"со");
  s.articles["Descend"] = nvl(s.articles["Descend"],"со");
  s.articles["Put"] = nvl(s.articles["Put"],"на");
  s.articles["PutAway"] = nvl(s.articles["PutAway"],"на");
  s.articles["PutIn"] = nvl(s.articles["PutIn"],"на");
  s.articles["Sit"] = nvl(s.articles["Sit"],"на");
  s.articles["Lie"] = nvl(s.articles["Lie"],"на");
  s.Lie = nvl(s.Lie, "Сомневаюсь, что можно лечь на стул. Какие странные мысли приходят мне в голову.");
  s.Ascend = nvl(s.Ascend, redirect_("Lie"));
  s.Sit = nvl(s.Sit,
    rnd_ {
      "Я присаживаюсь на стул и несколько минут сижу, задумавшись.",
      "Я сажусь на стул, но тут же вновь вновь поднимаюсь на ноги.",
      "Честно говоря, я предпочёл бы постоять на ногах."
    });
  s.Stand = nvl(s.Stand, nilfn);
  s.Descend = nvl(s.Descend, redirect_("Stand"));
  s.Move = nvl(s.Move, "Я передвигаю стул, и его расставленные ножки царапают пол, вызывая неприятный надсадный скрип.");
  s.Take = nvl(s.Take, "Как-то мне не очень хочется таскать с собой этот стул.");
  return s;
end

function pHang(s)
  pBasic(s);
  s.break_ = true;
  s.withThrow = true;
  s.withPure = true;
  s.articles["Walk"] = nvl(s.articles["Walk"],"к");
  s.articles["Pure"] = nvl(s.articles["Pure"],"на");
  s.articles["Search"] = nvl(s.articles["Search"],"под");
  s.articles["Throw"] = nvl(s.articles["Throw"],"в");
  s.Open = nvl(s.Open, nilfn);
  s.Close = nvl(s.Close, nilfn);
  s.Take = nvl(s.Take, nilfn);
  s.Wreck = nvl(s.Wreck, nilfn);
  s.TakeOff = nvl(s.TakeOff, redirect_("Take"));
  s.TearOff = nvl(s.TearOff, redirect_("Take"));
  return s;
end

--Any electronic device
function pDevice(s)
  s.Approach = nvl(s.Approach, redirect_("Exam"));
  pBasic(s);
  s.break_ = true;
  s.withThrow = true;
  s.withPure = true;
  s.withCrack = true;
  s.withOpen = true;
  s.articles["Throw"] = nvl(s.articles["Throw"],"в");
  s.articles["Walk"] = nvl(s.articles["Walk"],"к");
  s.articles["Ascend"] = nvl(s.articles["Ascend"],"на");
  s.articles["Pure"] = nvl(s.articles["Pure"],"на");
  s.articles["Search"] = nvl(s.articles["Search"],"под");
  s.TurnOn = nvl(s.TurnOn, nilfn);
  s.TurnOff = nvl(s.TurnOff, nilfn);
  s.Activate = nvl(s.Activate, nilfn);
  s.Wreck = nvl(s.Wreck, nilfn);
  s.Move = nvl(s.Move, nilfn);
  s.Ascend = nvl(s.Ascend, nilfn);
  s.Open = nvl(s.Open, nilfn);
  s.Close = nvl(s.Close, nilfn);
  return s;
end

function pTablet(s)
  s.Tear = nvl(s.Tear, "Зачем же я буду портить свой планшет?");
  s.Exam = nvl(s.Exam,
    [[Планшетный компьютер, который выдают всем студентам нашего института -- простенькая и
      непритязательная модель. Почти все полезные приложения заблокированы, выхода во внешнюю сеть нет. Хорошо
      хоть почту оставили -- да и та с бессовестными фильтрами. В общем, ничего интересного. Единственный
      его плюс -- большой экран. Планшет можно разложить, как триптих, и тогда удобно читать научные
      статьи с графиками или смотреть учебные фильмы; в свёрнутом же состоянии планшет весьма компактен
      и без проблем влезает в карман пиджака.]]);
  pBasic(s);
  s.break_ = true;
  s.kind_ = "tablet";
  s.withPure = true;
  s.withKick = true;
  s.withOpen = true;
  s.withCrack = true;
  s.withPhoto = true;
  s.withFilm = true;
  s.articles["Pure"] = nvl(s.articles["Pure"],"на");
  s.articles["Search"] = nvl(s.articles["Search"],"в");
  s.articles["Call"] = nvl(s.articles["Call"],"по");
  s.articles["Write"] = nvl(s.articles["Write"],"в");
  s.articles["Photo"] = nvl(s.articles["Photo"],"на");
  s.articles["Film"] = nvl(s.articles["Film"],"на");
  s.Put = nvl(s.Put,
    function(s,v)
      local hw = here();
      if v.kind_ == "pocket" then
        return redirect_("Close")(s);
      elseif v.kind_ == "table" then
        return redirect_("Open")(s);
      else
        return [[Я бы предпочёл оставить планшет при себе.]];
      end
    end);
  s.Close = nvl(s.Close,
    function(s)
      local hw = here();
      if hw.kind_ == "classroom" then
        return 
          [[Я сворачиваю планшет, как триптих, и убираю его в карман, но спустя несколько секунд вновь достаю
            планшет из кармана. Да, хотя большинство приложений и заблокировано, без планшета на лекциях всё-таки
            слишком скучно.]];
      else
        return [[Планшет и так лежит у меня в кармане.]]
      end
    end);
  s.Open = nvl(s.Open,
    function(s)
      local hw = here();
      if hw.kind_ == "classroom" then
        return 
          [[Планшет уже раскрыт и лежит передо мной на столе.]];
      else
        return 
          [[Я вытаскиваю планшет из кармана, раскрываю экран и быстро проверяю все системные сообщения.
            Нет, ничего интересного.]]
      end
    end);
  s.TakeFrom = nvl(s.TakeFrom,
    function(s,v)
      if not v or v.kind_ == "pocket" then
        return redirect_("Open")(s);
      else
        return "Не представляю, как это сделать.";
      end
    end);
  s.Move = nvl(s.Move,
    function(s)
      local hw = here();
      if hw.kind_ == "classroom" then
        return [[От скуки я перекладываю планшет с места на место.]];
      else
        return [[Я перекладываю планшет из одной руки в другую.]];
      end
    end);
  s.Take = nvl(s.Take,
    function(s)
      local hw = here();
      if hw.kind_ == "classroom" then
        return redirect_("Close")(s);
      else
        return redirect_("Open")(s);
      end
    end);
  s.Throw = nvl(s.Throw,
    function(s,v)
      if not v then
        return [[Зачем мне выбрасывать свой планшет?]];
      elseif v.npc_ == "victor" then
        return 
          [[Ударить друга планшетом? Виктор, конечно, иногда меня порядочно достает, но всё же не до такой степени.
            Да и планшет жалко.]];
      elseif v.npc_ == "sokolovsky" then
        return
          [[Будь моя воля, я бы бросил в него чем-то более тяжёлым, но получать дисциплинарное взыскание я не собираюсь.]];
      elseif v.npc_ == "lydia" then
        return [[Не надо сходить с ума.]];
      elseif v.npc_ == "anna" then
        return [[Да уж, это точно позволит растопить лёд между нами.]];
      elseif v.kind_ == "human" then
        return [[Я предпочитаю не бросаться в людей планшетами.]];
      else
        return redirect_("Put")(s,v);
      end
    end);
  s.Give = nvl(s.Give,
    function(s,v)
      if v.npc_ == "victor" then
        return [[У Виктора есть свой планшет.]];
      elseif v.npc_ == "sokolovsky" then
        return [[Не очень понимаю, зачем мне отдавать свой студенческий планшет профессору.]];
      elseif v.npc_ == "lydia" then
        return [[Сомневаюсь, что ей нужен мой планшет.]];
      elseif v.npc_ == "anna" then
        return [[Обойдётся.]];
      else
        return [[Я бы предпочёл оставить свой планшет при себе.]];
      end 
    end);
  s.Search = nvl(s.Search, "У меня сейчас нет желания просматривать сайты нашего интранета. Там всё равно нет ничего интересного.");
  s.PutIn = nvl(s.PutIn, redirect_("Put"));
  s.PutAway = nvl(s.PutAway, redirect_("Put"));
  s.TurnOn = nvl(s.TurnOn, "Планшет включается и выключается автоматически.");
  s.TurnOff = nvl(s.TurnOff, redirect_("TurnOn"));
  s.Activate = nvl(s.Activate, redirect_("TurnOn"));
  s.Spin = nvl(s.Spin, redirect_("Move"));
  s.Fetch = nvl(s.Fetch, redirect_("Give"));
  return s;
end

--Any subject a hero can think of
function pThink(s)
  s.articles["Think"] = nvl(s.articles["Think"],"о");
  s.Invent = nvl(s.Invent, redirect_("Think"));
  return s;
end

function pRoom(s)
  pBasic(s);
  s.articles["Walk"] = nvl(s.articles["Walk"],"по");
  s.articles["WalkAround"] = nvl(s.articles["WalkAround"],"по");
  s.articles["Search"] = nvl(s.articles["Search"],"в");
  s.Walk = nvl(s.Walk, redirect_("Exam"));
  s.WalkAround = nvl(s.WalkAround, redirect_("Walk"));
  s.Approach = nil;
  return s;
end

function pHuman(s)
  s.Approach = nvl(s.Approach, redirect_("Talk"));
  pBasic(s);
  s.kind_ = "human";
  s.withThrow = true;
  s.withGive = true;
  s.withFetch = true;
  s.withPure = true;
  s.articles["Talk"] = nvl(s.articles["Talk"],"с");
  s.articles["Throw"] = nvl(s.articles["Throw"],"в");
  s.articles["Walk"] = nvl(s.articles["Walk"],"к");
  s.articles["Think"] = nvl(s.articles["Think"],"о");
  s.articles["Pure"] = nvl(s.articles["Pure"],"на");
  s.Attack = nvl(s.Attack, nilfn);
  s.Pounce = nvl(s.Pounce, redirect_("Attack"));
  s.Kick = nvl(s.Kick, redirect_("Attack"));
  s.Pure = nvl(s.Pure, nilfn);
  return s;
end

--Used for open/close eyes instances
function pEyes(s)
  s.Close = nvl(s.Close, "Мои глаза и так закрыты.");
  return s;
end

function pDoor(s)
  if s.Enter ~= nil then
    s.Walk = nvl(s.Walk, redirect_("Enter"));
  end
  if s.Exit ~= nil then
    s.Walk = nvl(s.Walk, redirect_("Exit"));
  end
  pBasic(s);
  s.kind_ = "door";
  s.withThrow = true;
  s.withPure = true;
  s.articles["Walk"] = nvl(s.articles["Walk"],"к");
  s.articles["Pure"] = nvl(s.articles["Pure"],"на");
  s.articles["Ascend"] = nvl(s.articles["Ascend"],"на");
  s.articles["Search"] = nvl(s.articles["Search"],"под");
  s.articles["Enter"] = nvl(s.articles["Enter"],"в");
  s.articles["Exit"] = nvl(s.articles["Exit"],"в");
  s.articles["Throw"] = nvl(s.articles["Throw"],"в");
  s.Open = nvl(s.Open, redirect_("Approach"));
  s.Close = nvl(s.Close, "Дверь и так закрыта.");
  s.Wreck = nvl(s.Wreck, "Не понимаю, зачем мне выламывать эту дверь.");
  s.Crack = nvl(s.Crack, "Не вижу смысла это делать.");
  s.Ascend = nvl(s.Ascend, "Мне кажется, немного странно даже думать о том, чтобы залезть на дверь. Какой в этом смысл?");
  s.Move = nvl(s.Move, "Я не представляю, как можно двигать двери.");
  return s;
end

function pDark(s)
  s.articles["Look"] = nvl(s.articles["Look"],"в");
  s.articles["Walk"] = nvl(s.articles["Walk"],"в");
  s.articles["Throw"] = nvl(s.articles["Throw"],"в");
  s.Approach = nvl(s.Approach, redirect_("Exam"));
  s.withThrow = true;
  pBasic(s);
  return true;
end

function pBed(s)
  s.Approach = nvl(s.Approach, redirect_("Exam"));
  pBasic(s);
  s.kind_ = "bed";
  s.break_ = true;
  s.withPut = true;
  s.withPutIn = true;
  s.withPutAway = true;
  s.withThrow = true;
  s.withPure = true;
  s.articles["Lie"] = nvl(s.articles["Lie"],"на");
  s.articles["Sit"] = nvl(s.articles["Sit"],"на");
  s.articles["Stand"] = nvl(s.articles["Stand"],"с");
  s.articles["Descend"] = nvl(s.articles["Descend"],"с");
  s.articles["Ascend"] = nvl(s.articles["Ascend"],"на");
  s.articles["Throw"] = nvl(s.articles["Throw"],"на");
  s.articles["PutAway"] = nvl(s.articles["PutAway"],"на");
  s.articles["PutIn"] = nvl(s.articles["PutIn"],"на");
  s.articles["Put"] = nvl(s.articles["Put"],"на");
  s.articles["Pure"] = nvl(s.articles["Pure"],"на");
  s.articles["Search"] = nvl(s.articles["Search"],"под");
  s.articles["Walk"] = nvl(s.articles["Walk"],"к");
  s.Stand = nvl(s.Stand, nilfn);
  s.Lie = nvl(s.Lie, nilfn);
  s.Sit = nvl(s.Sit, nilfn);
  s.Descend = nvl(s.Descend, nilfn);
  s.Ascend = nvl(s.Ascend, nilfn);
  s.Wreck = nvl(s.Wreck, nilfn);
  s.Move = nvl(s.Move, nilfn);
  s.Spin = nvl(s.Spin, nilfn);
  return s;
end

function pItem(s)
  pBasic(s);
  s.Take = nvl(s.Take, redirect_("Exam"));
  --s.TakeFrom = nvl(s.TakeFrom, redirect_("Take"));
  s.PutIn = nvl(s.PutIn, redirect_("Put"))
  s.PutAway = nvl(s.PutAway, redirect_("Put"))
  return s;
end

--Something that can be examined or listened to but that's it
function pPhenom(s)
  s.articles["Look"] = nvl(s.articles["Look"],"на");
  s.articles["ListenTo"] = nvl(s.articles["ListenTo"],"к");
  s.articles["Approach"] = nvl(s.articles["Approach"],"к");
  s.articles["Walk"] = nvl(s.articles["Walk"],"к");
  if s.Exam ~= nil then
    s.Look = nvl(s.Look, redirect_("Exam"));
  end
  if s.Listen ~= nil then
    s.ListenTo = nvl(s.ListenTo, redirect_("Listen"));
  end
  return s;
end

--A location where a hero can go
function pLocation(s)
  s.articles["Walk"] = nvl(s.articles["Walk"],"в");
  s.articles["Exit"] = nvl(s.articles["Exit"],"в");
  s.articles["Enter"] = nvl(s.articles["Enter"],"в");
  pBasic(s);
  if s.Exit ~= nil then
    s.Walk = nvl(s.Walk, redirect_("Exit"));
  end
  if s.Enter ~= nil then
    s.Walk = nvl(s.Walk, redirect_("Enter"));
  end
  return s;
end

----------------


function pFurniture(s)
  pBasic(s);
  s.weight = nvl(s.weight, 2);
  s.inrange = nvl(s.inrange, true);
  s.live = nvl(s.live, false);
  
  s.Wreck = nvl(s.Wreck, nilfn);
  s.withThrow = true;
  s.withPut   = true;
  s.withPure  = true;
  s.withPutIn = true;
  s.withPutAway = true;
  s.articles["Pure"] = nvl(s.articles["Pure"],"на");
  s.articles["Put"] = nvl(s.articles["Put"],"на");
  s.articles["Sit"] = nvl(s.articles["Sit"],"на");
  s.articles["Throw"] = nvl(s.articles["Throw"],"на");
  s.articles["Walk"] = nvl(s.articles["Walk"],"к");
  s.articles["Ascend"] = nvl(s.articles["Ascend"],"на");
  s.articles["Descend"] = nvl(s.articles["Descend"],"с");
  return s;
end


